package org.abettor.jroa.impl;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.abettor.jroa.Acceptor;
import org.abettor.jroa.AuthenticationException;
import org.abettor.jroa.Connection;
import org.abettor.jroa.Driver;
import org.abettor.jroa.UrlNotSupportException;

/**
 * <p>The implemention of the <i>Driver</i> interface
 * implemented by classes in package <i>java.net</i>.</p>
 * <p>All the mentioned <i>url</i> must match the format bellow:<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;<b><i>socket://[Host:]Port</i></b><br />
 * Here <i>Host</i> can be ether a domain name, a host name or an IP address.</p>
 * 
 * @see org.abettor.jroa.Driver
 * 
 * @author <a href="http://www.abettor.org/" target="_blank">abettor</a>
 *
 */
public class SocketDriver implements Driver
{
	/**
	 * @see org.abettor.jroa.Driver#bind(String)
	 */
	public Acceptor bind(String url) throws IOException, UrlNotSupportException
	{
		if(! support(url))
		{
			throw new UrlNotSupportException("URL [" + url +"] is not supported by driver");
		}

		int index1 = url.lastIndexOf(":");
		int index2 = url.lastIndexOf("/");
		int index = index1 > index2 ? index1 : index2;
		String port = url.substring(index + 1);

		InetSocketAddress isa = new InetSocketAddress(Integer.parseInt(port));
		ServerSocket socket = new ServerSocket();
		socket.setReuseAddress(true);
		socket.bind(isa);

		return new SocketAcceptor(socket);
	}

	/**
	 * @see org.abettor.jroa.Driver#connect(String, Properties)
	 */
	public Connection connect(String url, Properties prop) throws IOException, UrlNotSupportException, AuthenticationException
	{
		if(! support(url))
		{
			throw new UrlNotSupportException("URL [" + url +"] is not supported by driver");
		}

		int index1 = url.lastIndexOf(":");
		int index2 = url.lastIndexOf("/");
		int index = index1 > index2 ? index1 : index2;
		String port = url.substring(index + 1);

		int start = "socket://".length();
		if(index1 < start)
		{
			throw new UrlNotSupportException("URL [" + url +"] is not supported by driver : Host must be assigned");
		}
		String host = url.substring(start, index1);

		InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName(host), Integer.parseInt(port));
		Socket socket = new Socket();
		socket.connect(isa);

		return new SocketConnection(socket);
	}

	/**
	 * @see org.abettor.jroa.Driver#support(String)
	 */
	public boolean support(String url)
	{
		String ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-1]\\d|22[0-3])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
		String domain = "[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*";
		Pattern pattern = Pattern.compile("^socket://(((" + ip + ")|(" + domain + ")):){0,1}[1-9][0-9]{0,4}");
		Matcher matcher = pattern.matcher(url);
		if(! matcher.matches())
		{
			return false;
		}

		return true;
	}

}
